﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using PeiYue.AuthHelper;
using PeiYue.AuthHelper.OverWrite;
using PeiYue.Common.Helper;
using PeiYue.IServices;
using PeiYue.Model;
using PeiYue.Model.ViewModels;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using PeiYue.Model.Dto.User;
using AutoMapper;

namespace PeiYue.Controllers
{
    /// <summary>
    /// 登录管理【无权限】
    /// </summary>
    [Produces("application/json")]
    [Route("api/Login")]
    [AllowAnonymous]
    public class LoginController : Controller
    {
        readonly ISysUserInfoServices _sysUserInfoServices;
        readonly IUserRoleServices _userRoleServices;
        readonly IRoleServices _roleServices;
        readonly PermissionRequirement _requirement;
        private readonly IRoleModulePermissionServices _roleModulePermissionServices;
        readonly IHttpContextAccessor _httpContext;
        readonly IMapper _mapper;


        /// <summary>
        /// 构造函数注入
        /// </summary>
        /// <param name="sysUserInfoServices"></param>
        /// <param name="userRoleServices"></param>
        /// <param name="roleServices"></param>
        /// <param name="requirement"></param>
        /// <param name="roleModulePermissionServices"></param>
        public LoginController(ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices, IRoleServices roleServices, PermissionRequirement requirement, IRoleModulePermissionServices roleModulePermissionServices, IHttpContextAccessor httpContext, IMapper mapper)
        {
            this._sysUserInfoServices = sysUserInfoServices;
            this._userRoleServices = userRoleServices;
            this._roleServices = roleServices;
            _requirement = requirement;
            _roleModulePermissionServices = roleModulePermissionServices;
            _httpContext = httpContext;
            this._mapper = mapper;
        }


        #region 获取token的第1种方法
        /// <summary>
        /// 获取JWT的方法1
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pass"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("Token")]
        public async Task<MessageModel<string>> GetJwtStr(string name, string pass)
        {
            string jwtStr = string.Empty;
            bool suc = false;
            //这里就是用户登陆以后，通过数据库去调取数据，分配权限的操作

            var user = await _sysUserInfoServices.GetUserRoleNameStr(name, MD5Helper.MD5Encrypt32(pass));
            if (user != null)
            {

                TokenModelJwt tokenModel = new TokenModelJwt { Uid = 1, Role = user };

                jwtStr = JwtHelper.IssueJwt(tokenModel);
                suc = true;
            }
            else
            {
                jwtStr = "login fail!!!";
            }

            return new MessageModel<string>()
            {
                success = suc,
                msg = suc ? "获取成功" : "获取失败",
                response = jwtStr
            };
        }


        /// <summary>
        /// 获取JWT的方法2：给Nuxt提供
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pass"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("GetTokenNuxt")]
        public MessageModel<string> GetJwtStrForNuxt(string name, string pass)
        {
            string jwtStr = string.Empty;
            bool suc = false;
            //这里就是用户登陆以后，通过数据库去调取数据，分配权限的操作
            //这里直接写死了
            if (name == "admins" && pass == "admins")
            {
                TokenModelJwt tokenModel = new TokenModelJwt
                {
                    Uid = 1,
                    Role = "Admin"
                };

                jwtStr = JwtHelper.IssueJwt(tokenModel);
                suc = true;
            }
            else
            {
                jwtStr = "login fail!!!";
            }
            var result = new
            {
                data = new { success = suc, token = jwtStr }
            };

            return new MessageModel<string>()
            {
                success = suc,
                msg = suc ? "获取成功" : "获取失败",
                response = jwtStr
            };
        }
        #endregion



        /// <summary>
        /// 获取JWT的方法3：整个系统主要方法
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("PYLogin")]
        public async Task<MessageModel<TokenInfoViewModel>> GetJwtToken3([FromBody] LoginDto dto)
        {
            string jwtStr = string.Empty;
            string name = dto.name;
            string pass = dto.pass;
            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(pass))
            {
                return new MessageModel<TokenInfoViewModel>()
                {
                    success = false,
                    msg = "用户名或密码不能为空",
                };
            }

            pass = MD5Helper.MD5Encrypt32(pass);

            var user = await _sysUserInfoServices.Query(d => d.uLoginName == name && d.uLoginPWD == pass && d.uStatus == 1);
            if (user.Count > 0)
            {
                var u = user.FirstOrDefault();
                var userRoles = await _sysUserInfoServices.GetUserRoleNameStr(name, pass);
                //如果是基于用户的授权策略，这里要添加用户;如果是基于角色的授权策略，这里要添加角色
                var claims = new List<Claim> {
                    //new Claim(ClaimTypes.Name, name),
                    new Claim(IdentityModel.JwtClaimTypes.Name, name),
                    new Claim(JwtRegisteredClaimNames.Prn, user.FirstOrDefault().uRealName.ToString()),
                    new Claim(JwtRegisteredClaimNames.Jti, user.FirstOrDefault().uID.ToString()),
                    new Claim(JwtRegisteredClaimNames.Aud, user.FirstOrDefault().res_id.ToString()),
                    new Claim(JwtRegisteredClaimNames.Typ, user.FirstOrDefault().types.ToString()),
                    new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
                claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));


                // ids4和jwt切换
                // jwt
                if (!Permissions.IsUseIds4)
                {
                    var data = await _roleModulePermissionServices.RoleModuleMaps();
                    var list = (from item in data
                                where item.IsDeleted == false
                                orderby item.Id
                                select new PermissionItem
                                {
                                    Url = item.Module?.LinkUrl,
                                    Role = item.Role?.Name.ObjToString(),
                                }).ToList();

                    _requirement.Permissions = list;
                }

                var token = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
                token.types = u.types;
                token.UseDto = _mapper.Map<sysUserInfoDto>(u);
                return new MessageModel<TokenInfoViewModel>()
                { success = true, msg = "获取成功", response = token };
            }
            else
            {
                return new MessageModel<TokenInfoViewModel>()
                { success = false, msg = "认证失败", status = 301 };
            }
        }




        /// <summary>
        /// 请求刷新Token（以旧换新）
        /// </summary> 
        /// <param name="token">token</param>
        /// <param name="IsReturn">是否换新</param>
        /// <returns></returns>
        [HttpGet]
        [Route("RefreshToken")]
        public async Task<MessageModel<TokenInfoViewModel>> RefreshToken(string token = "", bool IsReturn = false)
        {
            string jwtStr = string.Empty;
            //string token = _httpContext.HttpContext.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "");
            if (string.IsNullOrEmpty(token))
            {
                return new MessageModel<TokenInfoViewModel>()
                {
                    success = false,
                    msg = "token无效，请重新登录！",
                };
            }
            var tokenModel = JwtHelper.SerializeJwt(token);
            if (tokenModel != null && tokenModel.Uid > 0)
            {
                var user = await _sysUserInfoServices.QueryById(tokenModel.Uid);
                if (user != null)
                {
                    var userRoles = await _sysUserInfoServices.GetUserRoleNameStr(user.uLoginName, user.uLoginPWD);
                    //如果是基于用户的授权策略，这里要添加用户;如果是基于角色的授权策略，这里要添加角色
                    var claims = new List<Claim> {
                    new Claim(ClaimTypes.Name, user.uLoginName),
                    new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjToString()),
                    new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
                    claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

                    //用户标识
                    var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
                    identity.AddClaims(claims);

                    var refreshToken = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
                    return new MessageModel<TokenInfoViewModel>()
                    {
                        success = true,
                        msg = "获取成功",
                        response = IsReturn ? refreshToken : (new TokenInfoViewModel())
                    };
                }
            }

            return new MessageModel<TokenInfoViewModel>()
            { success = false, msg = "认证失败！" };
        }



        /// <summary>
        /// 更新密码
        /// </summary> 
        /// <param name="oldPwd">旧密码</param>
        /// <param name="newPwd">新密码</param>
        /// <returns></returns>
        [HttpPost]
        [Route("UpdatePwd")]
        [Authorize(Permissions.Name)]
        public async Task<MessageModel<string>> UpdatePwd([FromBody] LoginDto dto)
        {
            string jwtStr = string.Empty;
            string token = _httpContext.HttpContext.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "");
            if (string.IsNullOrEmpty(token))
            {
                return new MessageModel<string>()
                { status = 301, success = false, msg = "token无效，请重新登录！", };
            }
            var tokenModel = JwtHelper.SerializeJwt(token);
            if (tokenModel != null && tokenModel.Uid > 0)
            {
                var user = await _sysUserInfoServices.QueryById(tokenModel.Uid);
                if (user != null)
                {
                    if (user.uLoginPWD != MD5Helper.MD5Encrypt32(dto.pass))
                        return new MessageModel<string>()
                        { status = 301, success = false, msg = "旧密码验证失败，请重输入！", };
                    user.uLoginPWD = MD5Helper.MD5Encrypt32(dto.newPwd);
                    user.update_user = user.uID;
                    user.uUpdateTime = DateTime.Now;
                    bool success = await _sysUserInfoServices.Update(user, new List<string> { "uLoginPWD", "update_time", "update_user" }, null);
                    return new MessageModel<string>()
                    { success = success, msg = "修改成功! " };
                }
            }

            return new MessageModel<string>()
            { success = false, msg = "认证失败！" };
        }


        ///// <summary>
        ///// 请求刷新Token（以旧换新）
        ///// </summary>
        ///// <param name="token"></param>
        ///// <param name="IsReturn">是否换新</param>
        ///// <returns></returns>
        //[HttpGet]
        //[Route("RefreshToken")]
        //public async Task<MessageModel<TokenInfoViewModel>> RefreshToken(string token = "", bool IsReturn = false)
        //{
        //    string jwtStr = string.Empty;

        //    if (string.IsNullOrEmpty(token))
        //    {
        //        return new MessageModel<TokenInfoViewModel>()
        //        {
        //            success = false,
        //            msg = "token无效，请重新登录！",
        //        };
        //    }
        //    var tokenModel = JwtHelper.SerializeJwt(token);
        //    if (tokenModel != null && tokenModel.Uid > 0)
        //    {
        //        var user = await _sysUserInfoServices.QueryById(tokenModel.Uid);
        //        if (user != null)
        //        {
        //            var userRoles = await _sysUserInfoServices.GetUserRoleNameStr(user.uLoginName, user.uLoginPWD);
        //            //如果是基于用户的授权策略，这里要添加用户;如果是基于角色的授权策略，这里要添加角色
        //            var claims = new List<Claim> {
        //            new Claim(ClaimTypes.Name, user.uLoginName),
        //            new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjToString()),
        //            new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
        //            claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

        //            //用户标识
        //            var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
        //            identity.AddClaims(claims);

        //            var refreshToken = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
        //            return new MessageModel<TokenInfoViewModel>()
        //            {
        //                success = true,
        //                msg = "获取成功",
        //                response = IsReturn ? (new TokenInfoViewModel()) : refreshToken
        //            };
        //        }
        //    }

        //    return new MessageModel<TokenInfoViewModel>()
        //    {
        //        success = false,
        //        msg = "认证失败！",
        //    };
        //}

        /// <summary>
        /// 获取JWT的方法4：给 JSONP 测试
        /// </summary>
        /// <param name="callBack"></param>
        /// <param name="id"></param>
        /// <param name="sub"></param>
        /// <param name="expiresSliding"></param>
        /// <param name="expiresAbsoulute"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("jsonp")]
        public void Getjsonp(string callBack, int id = 1, string sub = "Admin", int expiresSliding = 30, int expiresAbsoulute = 30)
        {
            TokenModelJwt tokenModel = new TokenModelJwt
            {
                Uid = id,
                Role = sub
            };

            string jwtStr = JwtHelper.IssueJwt(tokenModel);

            string response = string.Format("\"value\":\"{0}\"", jwtStr);
            string call = callBack + "({" + response + "})";
            Response.WriteAsync(call);
        }


        /// <summary>
        /// 测试 MD5 加密字符串
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("Md5Password")]
        public string Md5Password(string password = "")
        {
            return MD5Helper.MD5Encrypt32(password);
        }
    }
}